﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Runtime.InteropServices;
using Autodesk.Revit.DB;
using Autodesk.Revit.Exceptions;
using Autodesk.Revit.UI;
using Autodesk.Revit.UI.Selection;
using YArchitech.Controls;
using HYCodeBase.WinForm;
using YRevitJig;

namespace DrawZoneCom
{
	public class DrawZoneCom
	{
		[DllImport("user32.dll", EntryPoint = "SendMessageA")]
		public static extern int SendMessage(IntPtr hwnd, int wMsg, IntPtr wParam, IntPtr lParam);

		public static List<List<CurveLoop>> DrawZoneManual(UIApplication app, WindowHandle _hWndRevit)
		{
			UIDocument activeUIDocument = app.ActiveUIDocument;
			Document document = activeUIDocument.Document;
			Selection selection = activeUIDocument.Selection;
			DrawZoneCom.m_hWndRevit = _hWndRevit;
			DrawZoneForm drawZoneForm = new DrawZoneForm(DrawZoneCom.m_hWndRevit);
			drawZoneForm.Show(DrawZoneCom.m_hWndRevit);
			int wMsg = 7;
			DrawZoneCom.SendMessage(DrawZoneCom.m_hWndRevit.Handle, wMsg, IntPtr.Zero, IntPtr.Zero);
			List<List<CurveLoop>> list = new List<List<CurveLoop>>();
			List<ElementId> list2 = new List<ElementId>();
			TransactionGroup transactionGroup = new TransactionGroup(document, "TransactionGroup");
			transactionGroup.Start();
			XYZ xyz = XYZ.Zero;
			bool flag = true;
			for (;;)
			{
				try
				{
					if (drawZoneForm.m_eDrawMode == DrawMode.Line)
					{
						XLineJig xlineJig = new XLineJig(activeUIDocument);
						if (flag)
						{
							xlineJig.StartPoint = null;
							xyz = xlineJig.PickStartPoint("请确定直线起点：");
							if (xyz == null)
							{
								if (!DrawZoneCom.isCommandOver(drawZoneForm))
								{
									xlineJig.Dispose();
									continue;
								}
								xlineJig.Dispose();
								break;
							}
						}
						xlineJig.DrawSize = true;
						xlineJig.EndPoint = null;
						XYZ xyz2 = xlineJig.PickEndPoint(xyz, "请确定直线终点：");
						if (xyz2 == null)
						{
							if (!DrawZoneCom.isCommandOver(drawZoneForm))
							{
								xlineJig.Dispose();
								continue;
							}
							xlineJig.Dispose();
							break;
						}
						else
						{
							foreach (Curve curve in xlineJig.CreateCurves())
							{
								DetailCurve detailCurve = DrawZoneCom.CreateDetailCurve(document, curve);
								list2.Add(detailCurve.Id);
							}
							xyz = xyz2;
							flag = !drawZoneForm.Chain;
							xlineJig.Dispose();
						}
					}
					else if (DrawMode.Rect == drawZoneForm.m_eDrawMode)
					{
						XRectJigPtP xrectJigPtP = new XRectJigPtP(activeUIDocument);
						xrectJigPtP.StartPoint = null;
						XYZ xyz3 = xrectJigPtP.PickStartPointN("请确定矩形第一个角点：");
						if (xyz3 == null)
						{
							if (!DrawZoneCom.isCommandOver(drawZoneForm))
							{
								xrectJigPtP.Dispose();
								continue;
							}
							xrectJigPtP.Dispose();
							break;
						}
						else
						{
							xrectJigPtP.EndPoint = null;
							if (xrectJigPtP.PickEndPoint(xyz3, "请确定矩形另一对角点：") == null)
							{
								if (!DrawZoneCom.isCommandOver(drawZoneForm))
								{
									xrectJigPtP.Dispose();
									continue;
								}
								xrectJigPtP.Dispose();
								break;
							}
							else
							{
								foreach (Curve curve2 in xrectJigPtP.CreateCurves())
								{
									DetailCurve detailCurve2 = DrawZoneCom.CreateDetailCurve(document, curve2);
									list2.Add(detailCurve2.Id);
								}
								flag = true;
								xrectJigPtP.Dispose();
							}
						}
					}
					else if (DrawMode.Arc3Pt == drawZoneForm.m_eDrawMode)
					{
						XArc3PtJig xarc3PtJig = new XArc3PtJig(activeUIDocument);
						if (flag)
						{
							xarc3PtJig.StartPoint = null;
							xyz = xarc3PtJig.PickStartPoint("请确定圆弧起点：");
							if (xyz == null)
							{
								if (!DrawZoneCom.isCommandOver(drawZoneForm))
								{
									xarc3PtJig.Dispose();
									continue;
								}
								xarc3PtJig.Dispose();
								break;
							}
						}
						xarc3PtJig.EndPoint = null;
						XYZ xyz4 = xarc3PtJig.PickEndPoint(xyz, "请确定圆弧终点：");
						if (xyz4 == null)
						{
							if (!DrawZoneCom.isCommandOver(drawZoneForm))
							{
								xarc3PtJig.Dispose();
								continue;
							}
							xarc3PtJig.Dispose();
							break;
						}
						else
						{
							xarc3PtJig.OnCurvePoint = null;
							if (xarc3PtJig.PickOnCurvePoint(xyz, xyz4, "请确定圆弧上的点：") == null)
							{
								if (!DrawZoneCom.isCommandOver(drawZoneForm))
								{
									xarc3PtJig.Dispose();
									continue;
								}
								xarc3PtJig.Dispose();
								break;
							}
							else
							{
								foreach (Curve curve3 in xarc3PtJig.CreateCurves())
								{
									DetailCurve detailCurve3 = DrawZoneCom.CreateDetailCurve(document, curve3);
									list2.Add(detailCurve3.Id);
								}
								xyz = xyz4;
								flag = !drawZoneForm.Chain;
								xarc3PtJig.Dispose();
							}
						}
					}
					else if (DrawMode.ArcCenter == drawZoneForm.m_eDrawMode)
					{
						XArcJig xarcJig = new XArcJig(activeUIDocument);
						xarcJig.CenterPoint = null;
						xyz = xarcJig.PickCenterPoint("请确定圆弧中心点：");
						if (xyz == null)
						{
							if (!DrawZoneCom.isCommandOver(drawZoneForm))
							{
								xarcJig.Dispose();
								continue;
							}
							xarcJig.Dispose();
							break;
						}
						else
						{
							xarcJig.StartPoint = null;
							XYZ xyz5 = xarcJig.PickStartPoint(xyz, "请确定圆弧起点：");
							if (xyz5 == null)
							{
								if (!DrawZoneCom.isCommandOver(drawZoneForm))
								{
									xarcJig.Dispose();
									continue;
								}
								xarcJig.Dispose();
								break;
							}
							else
							{
								xarcJig.EndPoint = null;
								if (xarcJig.PickEndPoint(xyz, xyz5, "请确定圆弧终点：") == null)
								{
									if (!DrawZoneCom.isCommandOver(drawZoneForm))
									{
										xarcJig.Dispose();
										continue;
									}
									xarcJig.Dispose();
									break;
								}
								else
								{
									foreach (Curve curve4 in xarcJig.CreateCurves())
									{
										DetailCurve detailCurve4 = DrawZoneCom.CreateDetailCurve(document, curve4);
										list2.Add(detailCurve4.Id);
									}
									flag = true;
									xarcJig.Dispose();
								}
							}
						}
					}
					else
					{
						if (DrawMode.Delete == drawZoneForm.m_eDrawMode)
						{
							DetailCurveFilter detailCurveFilter = new DetailCurveFilter();
							IEnumerable<Element> enumerable = selection.PickElementsByRectangle(detailCurveFilter, "请框选需要删除的面积边线");
							Transaction transaction = new Transaction(document, "DeleteElements");
							transaction.Start();
							foreach (Element element in enumerable)
							{
								list2.Remove(element.Id);
								document.Delete(element.Id);
							}
							transaction.Commit();
							flag = true;
							continue;
						}
						if (DrawMode.Finish == drawZoneForm.m_eDrawMode)
						{
							List<Curve> list3 = new List<Curve>();
							foreach (ElementId elementId in list2)
							{
								DetailCurve detailCurve5 = document.GetElement(elementId) as DetailCurve;
								list3.Add(detailCurve5.GeometryCurve);
							}
							bool flag2 = true;
							List<RichPoint> list4 = DrawZoneCom.ConstructRichPointSet(list3);
							using (List<RichPoint>.Enumerator enumerator4 = list4.GetEnumerator())
							{
								while (enumerator4.MoveNext())
								{
									if (enumerator4.Current.m_curves.Count < 2)
									{
										flag2 = false;
										break;
									}
								}
							}
							if (!flag2)
							{
								YJKMessageBox.Show("区域不闭合。");
								drawZoneForm.m_eDrawMode = drawZoneForm.GetChecked();
								continue;
							}
							list4.Sort(new RichPointComparer());
							List<ClosedArea> closedAreas = DrawZoneCom.GetClosedAreas(list4);
							Transaction transaction2 = new Transaction(document, "CreateFilledRegion");
							transaction2.Start();
							document.Delete(list2);
							transaction2.Commit();
							foreach (ClosedArea closedArea in closedAreas)
							{
								list.Add(closedArea.getCurveLoopList());
							}
							transactionGroup.Commit();
							transactionGroup.Start();
							drawZoneForm.m_eDrawMode = drawZoneForm.GetChecked();
							list2 = new List<ElementId>();
							flag = true;
							drawZoneForm.Close();
							break;
						}
					}
					if (DrawZoneCom.IsClosed(document, list2))
					{
						flag = true;
					}
					continue;
				}
				catch (Autodesk.Revit.Exceptions.OperationCanceledException)
				{
					if (drawZoneForm.m_clickMode)
					{
						drawZoneForm.m_clickMode = false;
						continue;
					}
					transactionGroup.RollBack();
					drawZoneForm.Close();
					return list;
				}
				catch (Exception)
				{
					continue;
				}
				break;
			}
			transactionGroup.RollBack();
			drawZoneForm.Close();
			return list;
		}

		private static bool isCommandOver(DrawZoneForm dlgDraw)
		{
			if (dlgDraw.m_clickMode)
			{
				dlgDraw.m_clickMode = false;
				return false;
			}
			return true;
		}

		public static bool IsClosed(Autodesk.Revit.DB.Document doc, List<ElementId> ids)
		{
			List<Curve> list = new List<Curve>();
			foreach (ElementId elementId in ids)
			{
				DetailCurve detailCurve = doc.GetElement(elementId) as DetailCurve;
				list.Add(detailCurve.GeometryCurve);
			}
			string empty = string.Empty;
			return DrawZoneCom.SerializeCurves(list, ref empty);
		}

		public static bool SerializeCurves(List<Curve> curves, ref string message)
		{
			if (curves.Count == 0)
			{
				message = "曲线数量为0";
				return false;
			}
			Dictionary<XYZ, List<Curve>> dictionary = new Dictionary<XYZ, List<Curve>>(new XYZEqualityComparer());
			foreach (Curve curve in curves)
			{
				XYZ endPoint = curve.GetEndPoint(0);
				XYZ endPoint2 = curve.GetEndPoint(1);
				if (!dictionary.ContainsKey(endPoint))
				{
					dictionary.Add(endPoint, new List<Curve>
					{
						curve
					});
				}
				else
				{
					dictionary[endPoint].Add(curve);
				}
				if (!dictionary.ContainsKey(endPoint2))
				{
					dictionary.Add(endPoint2, new List<Curve>
					{
						curve
					});
				}
				else
				{
					dictionary[endPoint2].Add(curve);
				}
			}
			foreach (KeyValuePair<XYZ, List<Curve>> keyValuePair in dictionary)
			{
				XYZ key = keyValuePair.Key;
				List<Curve> value = keyValuePair.Value;
				if (value.Count > 2)
				{
					message = "所选参照线重叠或者存在分支";
					return false;
				}
				if (value.Count == 1)
				{
					message = "所选参照线不是环线";
					return false;
				}
			}
			return true;
		}

		public static List<ClosedArea> GetClosedAreas(List<RichPoint> richPoints)
		{
			List<ClosedArea> list = new List<ClosedArea>();
			while (richPoints.Count > 1)
			{
				List<Curve> list2 = DrawZoneCom.SearchLongestPath(richPoints);
				int num = -1;
				if (list.Count > 0)
				{
					ClosedArea closedArea = list[list.Count - 1];
					List<XYZ> list3 = new List<XYZ>();
					foreach (Curve curve in closedArea.m_outerBoundary)
					{
						list3.AddRange(curve.Tessellate());
					}
					list2[0].GetEndPoint(0);
				}
				if (1 == num)
				{
					list[list.Count - 1].m_innerBoundary.Add(list2);
				}
				else if (-1 == num)
				{
					ClosedArea closedArea2 = new ClosedArea();
					closedArea2.m_outerBoundary = new List<Curve>();
					closedArea2.m_outerBoundary.AddRange(list2);
					closedArea2.m_innerBoundary = new List<List<Curve>>();
					list.Add(closedArea2);
				}
				foreach (Curve curve2 in list2)
				{
					XYZ ptStart = curve2.GetEndPoint(0);
					int num2 = richPoints.FindIndex((RichPoint a) => a.m_point.IsAlmostEqualTo(ptStart));
					if (-1 != num2)
					{
						foreach (Curve curve3 in richPoints[num2].m_curves)
						{
							XYZ ptEnd = curve3.GetEndPoint(1);
							RichPoint richPoint = richPoints.Find((RichPoint a) => a.m_point.IsAlmostEqualTo(ptEnd));
							for (int i = 0; i < richPoint.m_curves.Count; i++)
							{
								if (richPoint.m_curves[i].GetEndPoint(1).IsAlmostEqualTo(ptStart))
								{
									richPoint.m_curves.RemoveAt(i);
									break;
								}
							}
						}
						richPoints.RemoveAt(num2);
					}
				}
				DrawZoneCom.DeleteSingleEdgePoint(ref richPoints);
			}
			return list;
		}

		private static void DeleteSingleEdgePoint(ref List<RichPoint> richPoints)
		{
			for (int i = 0; i < richPoints.Count; i++)
			{
				RichPoint richPoint = richPoints[i];
				if (1 == richPoint.m_curves.Count)
				{
					XYZ endPoint = richPoint.m_curves[0].GetEndPoint(0);
					XYZ ptEnd = richPoint.m_curves[0].GetEndPoint(1);
					richPoints.RemoveAt(i);
					i--;
					RichPoint richPoint2 = richPoints.Find((RichPoint a) => a.m_point.IsAlmostEqualTo(ptEnd));
					for (int j = 0; j < richPoint2.m_curves.Count; j++)
					{
						if (richPoint2.m_curves[j].GetEndPoint(1).IsAlmostEqualTo(endPoint))
						{
							richPoint2.m_curves.RemoveAt(j);
							if (richPoint2.m_curves.Count == 0)
							{
								richPoints.Remove(richPoint2);
							}
							i = -1;
							break;
						}
					}
				}
			}
			richPoints.TrimExcess();
		}

		private static List<Curve> SearchLongestPath(List<RichPoint> richPoints)
		{
			XYZ xyz = XYZ.BasisY.Negate();
			double num = 0.0;
			List<Curve> list = new List<Curve>();
			Curve curve = null;
			XYZ ptCurrent = richPoints[0].m_point;
            Predicate<RichPoint> ss9__0 = null;
			do
			{
				Predicate<RichPoint> match;
				if ((match = ss9__0) == null)
				{
					match = (ss9__0 = ((RichPoint a) => a.m_point.IsAlmostEqualTo(ptCurrent)));
				}
				foreach (Curve curve2 in richPoints.Find(match).m_curves)
				{
					XYZ tangentAt = DrawZoneCom.GetTangentAt(curve2);
					double num2 = xyz.AngleOnPlaneTo(tangentAt, XYZ.BasisZ);
					if (Math.Round(Math.PI*2, 4) == Math.Round(num2, 4))
					{
						num2 = 0.0;
					}
					if (num2 > num)
					{
						curve = curve2;
						num = num2;
					}
				}
				list.Add(curve);
				ptCurrent = curve.GetEndPoint(1);
				xyz = DrawZoneCom.GetTangentAt(DrawZoneCom.CreateReversedCurve(curve));
				num = 0.0;
			}
			while (!ptCurrent.IsAlmostEqualTo(richPoints[0].m_point));
			return list;
		}

		private static XYZ GetTangentAt(Curve curve)
		{
			return curve.ComputeDerivatives(0.0, true).BasisX.Normalize();
		}

		private static DetailCurve CreateDetailCurve(Autodesk.Revit.DB.Document doc, Curve curve)
		{
			System.Drawing.Color.FromArgb(255, 0, 255);
			Transaction transaction = new Transaction(doc, "DrawCurve");
			transaction.Start();
			DetailCurve result = doc.Create.NewDetailCurve(doc.ActiveView, curve);
			transaction.Commit();
			return result;
		}

		public static List<Line> CreateRect(XYZ pt1, XYZ pt2)
		{
			XYZ xyz = new XYZ(pt1.X, pt2.Y, pt1.Z);
			XYZ xyz2 = new XYZ(pt2.X, pt1.Y, pt1.Z);
			return new List<Line>
			{
				Line.CreateBound(pt1, xyz),
				Line.CreateBound(xyz, pt2),
				Line.CreateBound(pt2, xyz2),
				Line.CreateBound(xyz2, pt1)
			};
		}

		public static Arc CreateArc(XYZ ptCenter, XYZ ptArcStart, XYZ ptArcEnd)
		{
			double length = (ptArcStart - ptCenter).GetLength();
			XYZ xyz = ptArcStart - ptCenter;
			XYZ xyz2 = ptArcEnd - ptCenter;
			xyz.AngleOnPlaneTo(xyz2, XYZ.BasisZ);
			double num;
			double num2;
			if (xyz.AngleOnPlaneTo(xyz2, XYZ.BasisZ) <= Math.PI)
			{
				num = XYZ.BasisX.AngleOnPlaneTo(xyz, XYZ.BasisZ);
				num2 = XYZ.BasisX.AngleOnPlaneTo(xyz2, XYZ.BasisZ);
				if (num > num2)
				{
					num2 += Math.PI*2;
				}
				return Arc.Create(ptCenter, length, num, num2, XYZ.BasisX, XYZ.BasisY);
			}
			num = XYZ.BasisX.Negate().AngleOnPlaneTo(xyz, XYZ.BasisZ.Negate());
			num2 = XYZ.BasisX.Negate().AngleOnPlaneTo(xyz2, XYZ.BasisZ.Negate());
			if (num > num2)
			{
				num2 += Math.PI*2;
			}
			return Arc.Create(ptCenter, length, num, num2, XYZ.BasisX.Negate(), XYZ.BasisY);
		}

		public static List<RichPoint> ConstructRichPointSet(List<Curve> splitCurves)
		{
			List<RichPoint> list = new List<RichPoint>();
			foreach (Curve curve in splitCurves)
			{
				XYZ ptStart = curve.GetEndPoint(0);
				int num = list.FindIndex((RichPoint a) => a.m_point.IsAlmostEqualTo(ptStart));
				if (-1 == num)
				{
					list.Add(new RichPoint(ptStart, curve));
				}
				else
				{
					list[num].AddCurve(curve);
				}
				XYZ ptEnd = curve.GetEndPoint(1);
				num = list.FindIndex((RichPoint a) => a.m_point.IsAlmostEqualTo(ptEnd));
				if (-1 == num)
				{
					list.Add(new RichPoint(ptEnd, DrawZoneCom.CreateReversedCurve(curve)));
				}
				else
				{
					list[num].AddCurve(DrawZoneCom.CreateReversedCurve(curve));
				}
			}
			return list;
		}

		private static Curve CreateReversedCurve(Curve orig)
		{
			if (orig is Line)
			{
				return Line.CreateBound(orig.GetEndPoint(1), orig.GetEndPoint(0));
			}
			if (orig is Arc)
			{
				return Arc.Create(orig.GetEndPoint(1), orig.GetEndPoint(0), orig.Evaluate(0.5, true));
			}
			throw new Exception("无法创建方向相反的曲线。");
		}

		private bool GetShortestCurve(Curve curve1, Curve curve2, ref Curve shortestCurve)
		{
			XYZ endPoint = curve1.GetEndPoint(0);
			curve1.GetEndPoint(1);
			XYZ endPoint2 = curve2.GetEndPoint(0);
			curve2.GetEndPoint(1);
			XYZ endPoint3 = curve1.GetEndPoint(1);
			XYZ endPoint4 = curve2.GetEndPoint(0);
			if (endPoint3.DistanceTo(endPoint4) * 304.8 < 0.8)
			{
				shortestCurve = Line.CreateBound(endPoint, endPoint2);
				return false;
			}
			shortestCurve = Line.CreateBound(endPoint3, endPoint4);
			return true;
		}

		private Curve ExtendCurve(Curve curve, XYZ pt)
		{
			XYZ endPoint = curve.GetEndPoint(0);
			XYZ endPoint2 = curve.GetEndPoint(1);
			double num = endPoint.DistanceTo(pt);
			double num2 = endPoint2.DistanceTo(pt);
			if (num < 1E-05 || num2 < 1E-05)
			{
				return curve;
			}
			if (num > num2)
			{
				if (curve.GetType() == typeof(Line))
				{
					return Line.CreateBound(endPoint, pt);
				}
				if (curve.GetType() == typeof(Arc))
				{
					return Arc.Create(endPoint, pt, endPoint2);
				}
			}
			else
			{
				if (curve.GetType() == typeof(Line))
				{
					return Line.CreateBound(pt, endPoint2);
				}
				if (curve.GetType() == typeof(Arc))
				{
					return Arc.Create(pt, endPoint2, endPoint);
				}
			}
			return null;
		}

		private static WindowHandle m_hWndRevit;
	}
}
